package com.mnf.gui.controller;

import java.io.File;
import java.net.URL;
import java.util.ResourceBundle;

import com.mnf.server.component.MusicHttpServer;

import javafx.application.Platform;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.Slider;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaPlayer.Status;
import javafx.util.Duration;

public class MusicController {
	@FXML
	// ResourceBundle that was given to the FXMLLoader
	private ResourceBundle resources;
	@FXML
	// URL location of the FXML file that was given to the FXMLLoader
	private URL location;

	private String source;
	private String songName;
	private MediaPlayer mediaPlayer;

	/**
	 * Initializes the controller class.
	 */
	@FXML
	// This method is called by the FXMLLoader when initialization is complete
	void initialize() {
		initialMediaController();
	}

	/*
	 * MEDIA CONTROLLER
	 */
	@FXML
	private Label mediaStatus;
	@FXML
	private Button playButton;
	@FXML
	private Button stopButton;
	@FXML
	private Slider timeSlider;
	@FXML
	private Label playTime;
	@FXML
	private Slider volumeSlider;

	private final boolean repeat = false;
	private boolean stopRequested = false;
	private boolean atEndOfMedia = false;
	private Duration duration;
	
	private MusicHttpServer musicHttpServer;	

	private void initialMediaController() {
		File song = new File("resource/AfterTheFall-TwoStepsFromHell_phgz.mp3");
		source = song.toURI().toString();
		songName = song.getName();

		Media media = new Media(source);
		mediaPlayer = new MediaPlayer(media);

		playButton.getStyleClass().add("playButton");
		stopButton.getStyleClass().add("stopButton");

		mediaPlayer.currentTimeProperty().addListener(
				new ChangeListener<Duration>() {
					@Override
					public void changed(
							ObservableValue<? extends Duration> observable,
							Duration oldValue, Duration newValue) {
						updateValues();
						updateMediaStatus();
					}
				});
		mediaPlayer.setOnPlaying(new Runnable() {
			public void run() {
				if (stopRequested) {
					mediaPlayer.pause();
					stopRequested = false;
				} else {
					playButton.getStyleClass().clear();
					playButton.getStyleClass().add("pauseButton");
					// playButton.setText("||");
				}
				updateMediaStatus();
			}
		});
		mediaPlayer.setOnPaused(new Runnable() {
			public void run() {
				playButton.getStyleClass().clear();
				playButton.getStyleClass().add("playButton");
				// playButton.setText("||");
				updateMediaStatus();
			}
		});
		mediaPlayer.setOnReady(new Runnable() {
			public void run() {
				duration = mediaPlayer.getMedia().getDuration();
				updateValues();
				updateMediaStatus();
			}
		});

		mediaPlayer.setCycleCount(repeat ? MediaPlayer.INDEFINITE : 1);
		mediaPlayer.setOnEndOfMedia(new Runnable() {
			public void run() {
				if (!repeat) {
					playButton.getStyleClass().clear();
					playButton.getStyleClass().add("playButton");
					// playButton.setText(">");
					stopRequested = true;
					atEndOfMedia = true;
				}
				updateMediaStatus();
			}
		});

		// Time slider
		timeSlider.valueProperty().addListener(new InvalidationListener() {
			public void invalidated(Observable ov) {
				if (timeSlider.isValueChanging()) {
					// multiply duration by percentage calculated by slider
					// position
					if (duration != null) {
						mediaPlayer.seek(duration.multiply(timeSlider
								.getValue() / 100.0));
					}
					updateValues();

				}
			}
		});

		// Volume slider

		volumeSlider.valueProperty().addListener(new InvalidationListener() {
			public void invalidated(Observable ov) {
			}
		});
		volumeSlider.valueProperty().addListener(new ChangeListener<Number>() {
			@Override
			public void changed(ObservableValue<? extends Number> observable,
					Number oldValue, Number newValue) {
				if (volumeSlider.isValueChanging()) {
					mediaPlayer.setVolume(volumeSlider.getValue() / 100.0);
				}
			}
		});
	}

	@FXML
	void playFired(ActionEvent event) {
		updateValues();
		Status status = mediaPlayer.getStatus();
		if (status == Status.UNKNOWN || status == Status.HALTED) {
			// don't do anything in these states
			return;
		}

		if (status == Status.PAUSED || status == Status.READY
				|| status == Status.STOPPED) {
			// rewind the movie if we're sitting at the end
			if (atEndOfMedia) {
				mediaPlayer.seek(mediaPlayer.getStartTime());
				atEndOfMedia = false;
				playButton.getStyleClass().clear();
				playButton.getStyleClass().add("playButton");
				// playButton.setText(">");
				updateValues();
			}
			mediaPlayer.play();
			playButton.getStyleClass().remove("playButton");
			playButton.getStyleClass().add("pauseButton");
			// playButton.setText("||");
		} else {
			mediaPlayer.pause();
		}
	}

	@FXML
	void stopFired(ActionEvent event) {
		if (mediaPlayer == null) {
			// Do nothing
			return;
		}

		switch (mediaPlayer.getStatus()) {
		case PLAYING:
		case PAUSED:
			mediaPlayer.stop();
			playButton.getStyleClass().remove("pauseButton");
			playButton.getStyleClass().add("playButton");
			break;
		default:
			break;
		}
	}

	protected void updateValues() {
		if (playTime != null && timeSlider != null && volumeSlider != null
				&& duration != null) {
			Platform.runLater(new Runnable() {
				public void run() {
					Duration currentTime = mediaPlayer.getCurrentTime();
					playTime.setText(formatTime(currentTime, duration));
					timeSlider.setDisable(duration.isUnknown());
					if (!timeSlider.isDisabled()
							&& duration.greaterThan(Duration.ZERO)
							&& !timeSlider.isValueChanging()) {
						timeSlider.setValue(currentTime.divide(
								duration.toMillis()).toMillis() * 100.0);
					}
					if (!volumeSlider.isValueChanging()) {
						volumeSlider.setValue((int) Math.round(mediaPlayer
								.getVolume() * 100));
					}
				}
			});
		}
	}

	private void updateMediaStatus() {
		Status s = mediaPlayer.getStatus();
		String text = "";
		switch (s) {
		case PLAYING:
			text = "Playing - " + songName;
			break;
		case PAUSED:
			text = "Paused - " + songName;
			break;
		case READY:
			text = "Ready - " + songName;
			break;
		case STOPPED:
			text = "Stopped - " + songName;
			break;
		case STALLED:
			text = "Buffered - " + songName;
			break;
		default:
			break;
		}
		mediaStatus.setText(text);
	}

	private String formatTime(Duration elapsed, Duration duration) {
		int intElapsed = (int) Math.floor(elapsed.toSeconds());
		int elapsedHours = intElapsed / (60 * 60);
		if (elapsedHours > 0) {
			intElapsed -= elapsedHours * 60 * 60;
		}
		int elapsedMinutes = intElapsed / 60;
		int elapsedSeconds = intElapsed - elapsedHours * 60 * 60
				- elapsedMinutes * 60;

		if (duration.greaterThan(Duration.ZERO)) {
			int intDuration = (int) Math.floor(duration.toSeconds());
			int durationHours = intDuration / (60 * 60);
			if (durationHours > 0) {
				intDuration -= durationHours * 60 * 60;
			}
			int durationMinutes = intDuration / 60;
			int durationSeconds = intDuration - durationHours * 60 * 60
					- durationMinutes * 60;

			if (durationHours > 0) {
				return String.format("%d:%02d:%02d/%d:%02d:%02d", elapsedHours,
						elapsedMinutes, elapsedSeconds, durationHours,
						durationMinutes, durationSeconds);
			} else {
				return String.format("%02d:%02d/%02d:%02d", elapsedMinutes,
						elapsedSeconds, durationMinutes, durationSeconds);
			}
		} else {
			if (elapsedHours > 0) {
				return String.format("%d:%02d:%02d", elapsedHours,
						elapsedMinutes, elapsedSeconds);
			} else {
				return String.format("%02d:%02d", elapsedMinutes,
						elapsedSeconds);
			}
		}
	}

	/*
	 * END MEDIA CONTROLLER
	 */
}
